package edu.mcw.rgd.clinminer.umls.domain;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;
import org.springframework.roo.addon.tostring.RooToString;
import org.springframework.transaction.annotation.Transactional;

import edu.mcw.rgd.clinminer.data.ClinminerException;
import edu.mcw.rgd.clinminer.domain.Study;
import edu.mcw.rgd.clinminer.umls.type.AUI;

@RooJavaBean
@RooToString
@RooJpaActiveRecord(persistenceUnit = "persistenceUnit", versionColumn = "")
@Table(name = "DATA_INDEX")
@NamedQueries({
		@NamedQuery(name = "deleteAllRecords", query = "DELETE FROM DataIndex i"),
		@NamedQuery(name = "getTotalCounts", query = "SELECT i.annotationTotalCount FROM DataIndex i WHERE i.aui=:aui"),
		@NamedQuery(name = "getStudyCounts", query = "SELECT i.annotationStudyCount FROM DataIndex i WHERE i.aui=:aui AND i.study=:study"),
		@NamedQuery(name = "findParents", query = "SELECT DISTINCT i.paui FROM DataIndex i WHERE i.aui=:aui AND i.study=:study"),
		@NamedQuery(name = "findChildren", query = "SELECT DISTINCT i.aui FROM DataIndex i WHERE i.paui=:aui AND i.study=:study"), })
public class DataIndex {
	@Id
	@GeneratedValue(generator = "Data_Index_IDs_Seq")
	@SequenceGenerator(name = "Data_Index_IDs_Seq", sequenceName = "Data_Index_IDs_Seq", allocationSize = 1)
	@Column(name = "data_index_id")
	private Long id;

	@Column(name = "AUI")
	private String aui;

	@Column(name = "PAUI")
	private String paui;

	@Column(name = "CUI")
	private String cui;

	@Column(name = "SAB")
	private String sab;

	@JoinColumn(name = "study")
	Study study;

	@Column(name = "ANNOTATION_COUNT")
	Integer annotationStudyCount;

	@Column(name = "TOTAL_COUNT")
	Integer annotationTotalCount;

	@Transactional
	public void clearTable() {
		entityManager().createQuery("DELETE FROM DataIndex").executeUpdate();
	}

	public static Integer getTotalCounts(AUI aui) {
		List<Integer> result = entityManager()
				.createNamedQuery("getTotalCounts", Integer.class)
				.setParameter("aui", aui.toString()).setMaxResults(1)
				.getResultList();
		if (result.isEmpty() || result.get(0) == null) {
			return 0;
		} else {
			return result.get(0);
		}
	}

	public static Integer getStudyCounts(AUI aui, Study study) {
		List<Integer> result = entityManager()
				.createNamedQuery("getStudyCounts", Integer.class)
				.setParameter("aui", aui.toString())
				.setParameter("study", study).setMaxResults(1).getResultList();
		if (result.isEmpty() || result.get(0) == null) {
			return 0;
		} else {
			return result.get(0);
		}
	}

	public static List<AUI> getParentAUIs(AUI nodeAui, Study study)
			throws ClinminerException {
		List<AUI> result = new ArrayList<AUI>();
		for (String sAui : entityManager()
				.createNamedQuery("findParents", String.class)
				.setParameter("aui", nodeAui.toString())
				.setParameter("study", study).getResultList()) {
			// the little oddity of UMLS
			// TODO:is this still valid here
			if (sAui == null) {
				continue;
			}
			result.add(new AUI(sAui));
		}
		return result;
	}

	public static List<AUI> getChildAUIs(AUI nodeAui, Study study)
			throws ClinminerException {
		List<AUI> result = new ArrayList<AUI>();
		for (String sAui : entityManager()
				.createNamedQuery("findChildren", String.class)
				.setParameter("aui", nodeAui.toString())
				.setParameter("study", study).getResultList()) {
			result.add(new AUI(sAui));
		}
		return result;
	}

	public static Set<AUI> getSiblingAUIs(AUI aui, Study study)
			throws ClinminerException {
		Set<AUI> result = new HashSet<AUI>();
		// for root terms there are no parents
		result.add(aui);
		for (AUI parent : getParentAUIs(aui, study)) {
			result.addAll(getChildAUIs(parent, study));
		}
		return result;
	}
}